const extend = require('extend');

const Role = require('./role');
const Team = require('./team');
const Game = require('./game');
const Messages = require('./messages');
const Dispatcher = require('./dispatcher');

class Room extends Dispatcher {
    constructor(server, creator, settings) {
        super();
        this.server = server;
        this.creator = creator;
        this.status = 'waiting';
        let role = new (this.server.config.Role || Role)(this.server, this, creator);
        this.roles = [ role ];
        this.teams = Team.createTeams(this.server, role);
        this.disposed = false;
        this.settings = extend(true, { publish: false }, settings);
        this.id = Room.newId(this.server);
        this.server.rooms.set(this.id, this);
        this.messages = new Messages();
        console.log(`用户${ creator.name || creator.id }创建了游戏房间${ this.id }`);
    }
    dispose() {
        super.dispose();
        this.disposed = true;
        this.teams.forEach(team => team.dispose());
        this.roles = [];
        this.server.rooms.delete(this.id);
        this.server.roomIds.push(this.id);
    }
    join(player) {
        if (this.teams.every(team => team.emptyCount === 0)) throw '此房间人数已满';
        if (this.status !== 'waiting') throw '此房间可能在游戏中,不能加入此房间';
        let team = this.teams.reduce((s, t, i) => this.teams[s].emptyCount >= t.emptyCount ? s : i, 0);
        let index = this.teams[team].emptyIndex;
        let role = new (this.server.config.Role || Role)(this.server, this, player, team, index);
        this.roles.push(role);
        this.teams[team].add(role);
        player.room = this;
        console.log(`用户${ player.name || player.id }加入了游戏房间${ this.id }`);
    }
    exit(role, focus = false) {
        if (this.disposed || !focus && this.game) throw '';
        if (!focus && this.creator === role.player) {
            this.dispose();
            console.log(`用户${ role.player.name || role.player.id }解散了游戏房间${ this.id }`);
        } else {
            this.roles.splice(this.roles.indexOf(role), 1);
            this.teams[role.team].remove(role);
            if (this.game) this.game.exit(role);
            delete role.player.room;
            console.log(`用户${ role.player.name || role.player.id }退出了游戏房间${ this.id }`);
            if (this.creator === role.player) {
                if (this.roles.length) {
                    this.creator = this.roles[0].player;
                } else {
                    this.dispose();
                }
            }
        }
    }
    start(role) {
        if (this.disposed) throw '';
        if (!this.canStart) throw '';
        if (this.creator.id !== role.player.id) throw '';
        if (this.server.config.team && this.server.config.team.sort && this.status === 'waiting') {
            this.status = 'sorting';
        } else {
            this.roles.forEach(role => role.confirm());
            this.game = new (this.server.config.Game || Game)(this.server, this);
            this.status = 'gaming';
            console.log(`游戏房间${ this.id }开始了新的游戏`);
        }
    }
    over() {
        if (!this.game) throw '';
        delete this.game;
        this.status = 'waiting';
    }
    move(role, team, index) {
        if (role.player === this.creator) {
            throw '';
        } else {
            if (this.teams[team].roles[index] === true) {
                this.teams[role.team].roles[role.index] = true;
                this.teams[team].roles[index] = role;
                role.team = team;
                role.index = index;
            } else {
                throw '';
            }
        }
    }
    disable(role, team, index) {
		if (role.player === this.creator && this.teams[team].roles[index] === true) {
            this.teams[team].roles[index] = false;
		} else {
		    throw '';
        }
    }
    enable(role, team, index) {
		if (role.player === this.creator && this.teams[team].roles[index] === false) {
			this.teams[team].roles[index] = true;
		} else {
			throw '';
		}
    }
    kick(role, team, index) {
        if (role.player === this.creator) {
            if (this.teams[team].roles[index] instanceof Role) {
                this.teams[team].roles[index].exit();
            } else {
                throw '';
            }
        } else {
            throw '';
        }
    }
    leave(force = false) {
        if (this.roles.every(role => role.player.leaved)) {
            if (this.roles.length > 1 || force) {
                if (this.game) this.game.over();
                this.roles.forEach(role => this.exit(role));
            } else {
                setTimeout(() => this.leave(true), 30000);
            }
        }
    }
    message(role, message) {
        this.messages.append({
            role: role.data,
            message: message
        });
    }
    get canStart() {
        let config = this.server.config;
        return !this.roles.some(role => role.player.leaved)
            && this.teams.every(team => team.count >= (config.team.min || 1))
            && new Set(this.teams.map(team => team.count)).size === 1
            && (!config.team.regroup || this.roles.length % Number(config.team.regroup) === 0);
    }
    get data() {
        return {
            id: this.id,
            creator: {
                id: this.creator.id,
                name: this.creator.name
            },
            settings: this.settings,
            canStart: this.canStart,
            teams: this.teams.map(team => team.data),
            game: this.game && this.game.data,
            status: this.status,
            messages: []
        }
    }
    get summary() {
        return {
            id: this.id,
            creator: {
                id: this.creator.id,
                name: this.creator.name
            },
            length: this.teams.map(team => team.openCount).reduce((s, t) => s + t, 0),
            empty: this.teams.map(team => team.emptyCount).reduce((s, t) => s + t, 0),
            status: this.status
        }
    }
    static get(server, gameId) {
        if (server.rooms.has(gameId)) {
            return server.rooms.get(gameId);
        } else {
            throw '无此游戏房间';
        }
    }
    static newId(server) {
        if (server.roomIds.length) return server.roomIds.pop();
        let size = Math.max(server.rooms.size, 999);
        let base = 10;
        while (size % base !== size) base *= 10;
        while(true) {
            let id = String(parseInt(Math.random() * size) + base);
            if (!server.rooms.has(id)) return id;
        }
    }
    static list(server, page) {
        let list = [];
        let current = 0;
        page = page || 0;
        for (let room of server.rooms.values()) {
            if (room.settings.publish) {
                if (current >= page * 20) {
                    list.push(room);
                }
                if (list.length === 20) {
                    return list;
                }
                current++
            }
        }
        return list;
    }
}
module.exports = Room;